use std::fs::{create_dir_all, remove_dir};

use data_transform::DefaultDataTransformer;
use datasource_connector::{
    connector::SimpleDataSourceConnector, modeling_connector::SimpleMetaConnector,
};
use model_graph_common::utils::{new_uuid, rrg01_home_path, zip::compress_dir};
use model_graph_types::{
    builder::configure::ServerConfigureOption,
    connector::{Connector, ExecuteOptionsBuilder},
    database::{ConnectorProtocol, DataSource, DatabaseType},
    datasource::{
        AttributeConditionBuilder, DataSourceConnector, InsertOptionsBuilder, QueryConditionBuilder,
    },
    modeling::{
        meta::SYSTEM_DOMAIN_IDENTIFIER,
        scheduler::{SchedulerTask, SchedulerTaskTemplate},
        system_meta_database,
        workflow::WorkflowEntity,
        ClassGetter, ComparsionOperator, MetaConnector, Value,
    },
    transform::{DomainTransformer, DomainTransformerOptionsBuilder, DomainTransformerUnitBuilder},
};
use union_connector::UnionConnector;

pub async fn export_server_config(
    meta_datasource: &DataSource,
    target: &String,
    export_options: ServerConfigureOption,
) -> anyhow::Result<i32> {
    //导出sqlite
    let temp_path = rrg01_home_path()?.join("temp").join(new_uuid()?);
    let _ = create_dir_all(temp_path.clone());

    let sqlite = format!(
        "{}/{}",
        temp_path
            .to_str()
            .map_or(Err(anyhow::anyhow!("获取程序目录失败")), |v| Ok(v))?,
        "rrg01.sqlite"
    );
    //创建空的数据库文件
    let _ = std::fs::File::create(temp_path.join("rrg01.sqlite"));

    let src_datasource = system_meta_database()?;

    let datasource2 = DataSource {
        id: 1,
        database_type: DatabaseType::SQLite,
        protocol: ConnectorProtocol::SQLite,
        url: format!("sqlite:{}", sqlite),
        ..Default::default()
    };

    //系统库的ddl执行
    let connector = SimpleMetaConnector::new_with_meta_datasource(&Some(src_datasource.clone()))?;

    //查询
    let sqls = connector
        .generate_sql(
            &String::from(SYSTEM_DOMAIN_IDENTIFIER),
            DatabaseType::SQLite,
        )
        .await?;

    let connector = UnionConnector::open(&datasource2).await.unwrap();
    let _ = connector
        .execute(
            &sqls.join(";\n"),
            &vec![],
            ExecuteOptionsBuilder::default().build()?,
        )
        .await?;

    //获取所有的知识域
    let domains = &export_options.domain.domains;

    let units = domains
        .iter()
        .filter_map(|d| {
            DomainTransformerUnitBuilder::default()
                .domain_identifier(d)
                .build()
                .ok()
        })
        .collect();

    let transform = DefaultDataTransformer::default();
    let options = DomainTransformerOptionsBuilder::default()
        .ignore_errs(true)
        .ddl(false)
        .build()?;

    let _ = transform
        .transform_domain(meta_datasource, &datasource2, units, options)
        .await;

    //获取所有的调度任务
    let task_ids = if let Some(scheduler) = &export_options.scheduler {
        &scheduler.tasks
    } else {
        &vec![]
    };
    // task路径
    let task_path = temp_path.join("tasks");
    let _ = create_dir_all(task_path.clone());

    let sdsc = SimpleDataSourceConnector::default();

    //导出tasks
    //获取所有的文件路径
    let tasks: Vec<SchedulerTask> = sdsc
        .instance_query(
            &Some(src_datasource.clone()),
            &src_datasource,
            &SchedulerTask::get_identifier()?,
            QueryConditionBuilder::default()
                .attributes(vec![AttributeConditionBuilder::default()
                    .name("identifier")
                    .operator(ComparsionOperator::In)
                    .values(task_ids.clone())
                    .build()?])
                .build()?,
            Some(SchedulerTask::common_query_extention()?),
            None,
        )
        .await?
        .data
        .iter()
        .filter_map(|f| f.clone().try_into().ok())
        .collect();
    tracing::debug!("{:?}", tasks);
    //拷贝文件
    for task in tasks {
        if let Some(template) = &task.template {
            let new_template = template.clone();

            if let Some(workflow) = &template.workflow {
                let path = &workflow.content;
                let to_path = format!(
                    "{}",
                    task_path
                        .join(format!("{}.json", workflow.identifier))
                        .to_str()
                        .map_or(Err(anyhow::anyhow!("获取程序目录失败")), |v| Ok(v))?,
                );
                tracing::debug!("{}->{}", path, to_path);
                //文件拷贝
                std::fs::copy(path, &to_path)
                    .map_err(|err| anyhow::anyhow!("文件拷贝失败[{}]:{}", path, err))?;

                //
                let mut workflow = workflow.clone();
                workflow.content = format!("tasks/{}.json", workflow.identifier);

                //
                //保存workflow
                sdsc.instance_insert(
                    &Some(src_datasource.clone()),
                    &datasource2,
                    &WorkflowEntity::get_identifier()?,
                    workflow.try_into()?,
                    Some(
                        InsertOptionsBuilder::default()
                            .ignores(vec![String::from("id")])
                            .build()?,
                    ),
                )
                .await?;
            }
            //更新
            //保存template
            sdsc.instance_insert(
                &Some(src_datasource.clone()),
                &datasource2,
                &SchedulerTaskTemplate::get_identifier()?,
                new_template.try_into()?,
                Some(
                    InsertOptionsBuilder::default()
                        .ignores(vec![String::from("id")])
                        .build()?,
                ),
            )
            .await?;
        }
        //保存task
        sdsc.instance_insert(
            &Some(src_datasource.clone()),
            &datasource2,
            &SchedulerTask::get_identifier()?,
            task.try_into()?,
            Some(
                InsertOptionsBuilder::default()
                    .ignores(vec![String::from("id")])
                    .build()?,
            ),
        )
        .await?;
    }

    //压缩目录
    compress_dir(
        temp_path
            .to_str()
            .map_or(Err(anyhow::anyhow!("获取程序目录失败")), |v| Ok(v))?,
        target.as_str(),
    )?;
    //移出目录
    let _ = remove_dir(temp_path);

    Ok(1)
}
